﻿using System;
using System.Text;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using ICeFramework.Common.DataLayer.Interfaces;
using ICeFramework.Common.DataLayer;

namespace ICeFramework.Business.DataLayer
{
    public interface IEntityObjectIdentificator
    {
        string Identificator { get; }
    }

    public class EntityRowBase<TEntity, TEntityRow> : System.ComponentModel.IComponent, IEntityObjectIdentificator, IEntityRow
        where TEntity : class
        where TEntityRow : class
    {
        #region public virtual string Identificator
        /// <summary>
        /// Gets the Identificator of the EntityObject
        /// </summary>
        /// <value></value>
        public virtual string Identificator
        {
            get
            {
                return this.ToString();
            }
        }
        #endregion

        private EntityObjectCollection _cells = new EntityObjectCollection();
        #region public EntityObjectCollection Cells
        /// <summary>
        /// Gets the Cells of the EntityRowBase
        /// </summary>
        /// <value></value>
        public EntityObjectCollection Cells
        {
            get { return _cells; }
        }
        #endregion

        private Dictionary<string, EntityBase<TEntity, TEntityRow>> _relatedEntities;
        #region protected Dictionary<string, Entity> RelatedEntities
        /// <summary>
        /// Gets the RelatedEntities of the EntityObject
        /// </summary>
        /// <value></value>
        protected Dictionary<string, EntityBase<TEntity, TEntityRow>> RelatedEntities
        {
            get
            {
                if (_relatedEntities == null)
                {
                    _relatedEntities = new Dictionary<string, EntityBase<TEntity, TEntityRow>>();
                }
                return _relatedEntities;
            }
        }
        #endregion

        private DataRow _dataRow;
        #region public DataRow DataRow
        /// <summary>
        /// Get/Sets the DataRow of the EntityRowBase
        /// </summary>
        /// <value></value>
        public DataRow DataRow
        {
            get { return _dataRow; }
            internal set { _dataRow = value; }
        }
        #endregion

        private EntityBase<TEntity, TEntityRow> _entity;
        #region public virtual EntityBase<TEntity, TEntityRow> Entity
        /// <summary>
        /// Gets the Entity of the EntityRowBase
        /// </summary>
        /// <value></value>
        public virtual EntityBase<TEntity, TEntityRow> Entity
        {
            get { return _entity; }
        }
        #endregion

        #region public DataRowState DataRowState
        /// <summary>
        /// Gets the DataRowState of the EntityObject
        /// </summary>
        /// <value></value>
        public DataRowState DataRowState
        {
            get { return _dataRow.RowState; }
        }
        #endregion

        #region public virtual bool IsValid
        /// <summary>
        /// Gets the IsValid of the EntityRowBase
        /// </summary>
        /// <value></value>
        public virtual bool IsValid
        {
            get { return GetErrors().Count == 0; }
        }
        #endregion

        #region public EntityRowErrorCollection GetErrors()
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public EntityRowErrorCollection GetErrors()
        {
            EntityRowErrorCollection errors = new EntityRowErrorCollection();
            foreach (IEntityObject item in this._cells)
            {
                if (!item.IsValid)
                {
                    errors.Add(item.ErrorCode, item.ErrorMessage);
                }
            }
            return errors;
        }
        #endregion

        #region public IEntityObject this[EntityColumn column]
        /// <summary>
        /// Gets the <see cref="IEntityObject"/> item identified by the given arguments of the EntityRowBase
        /// </summary>
        /// <value></value>
        public IEntityObject this[EntityColumn column]
        {
            get { return GetEntityObject(column); }
        }
        #endregion

        #region public IEntityObject this[int columnIndex]
        /// <summary>
        /// Gets the <see cref="IEntityObject"/> item identified by the given arguments of the EntityRowBase
        /// </summary>
        /// <value></value>
        public IEntityObject this[int columnIndex]
        {
            get { return _cells[columnIndex]; }
        }
        #endregion

        public IEntityObject this[string columnName]
        {
            get { return _cells[columnName]; }
        }

        //private IEntityObject GetObjectByColumn(string columnName)
        //{
        //    foreach (IEntityObject item in _cells)
        //    {
        //        if (item.Column.Name == columnName)
        //        {
        //            return item;
        //        }
        //    }
        //    return null;
        //}

         #region public EntityRowBase(EntityBase<TEntity, TEntityRow> entity, DataRow dataRow)
        /// <summary>
        /// Initializes a new instance of the <b>EntityRowBase&lt;TEntity, TEntityRow&gt;</b> class.
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="dataRow"></param>
        public EntityRowBase(EntityBase<TEntity, TEntityRow> entity, DataRow dataRow)
        {
            _entity = entity;
            _dataRow = dataRow;
            SetRowObjects();
        }
        #endregion


        #region private void SetRowObjects()
        /// <summary>
        /// 
        /// </summary>
        private void SetRowObjects()
        {
            foreach (EntityColumn column in _entity.Columns)
            {
                EntityObject<TEntity> item = (EntityObject<TEntity>)Activator.CreateInstance(typeof(EntityObject<TEntity>), this, column);
                //IEntityObject item = (IEntityObject)Activator.CreateInstance(typeof(EntityObject<TEntity>), this, column);
                _cells.Add(item);
            }
        }
        #endregion

        #region private EntityObject<TEntity> GetEntityObject(EntityColumn column)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="column"></param>
        /// <returns></returns>
        private EntityObject<TEntity> GetEntityObject(EntityColumn column)
        {
            foreach (EntityObject<TEntity> obj in _cells)
            {
                if (obj.Column.Name == column.Name)
                {
                    return obj;
                }
            }
            return null;
        }
        #endregion

        #region IEntityRow Members

        IEntity IEntityRow.Entity
        {
            get { return _entity; }
        }

        #endregion

        public void Save(IDbTransaction transaction)
        {
            _entity.Update(_dataRow, transaction);
        }

        #region IComponent Members

        public event EventHandler Disposed;

        private System.ComponentModel.ISite m_site = null;

        public System.ComponentModel.ISite Site
        {
            get
            {
                return m_site;
            }
            set
            {
                m_site = value;
            }
        }

        public void Dispose()
        {
            if (_relatedEntities != null)
            {
                _relatedEntities.Clear();
                _relatedEntities = null;
            }

            if (Disposed != null)
                Disposed(this, EventArgs.Empty);
        }

        #endregion
    }
}